/*
 * Project: Set Sample
 * Copyright (C) 2014 alf.labs gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.alflabs.setsample;

import android.app.Activity;
import android.app.Instrumentation.ActivityMonitor;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import com.alflabs.setsample.stats.GAHelper;
import com.jayway.android.robotium.solo.Solo;

//-----------------------------------------------

public class SoloTestCase<A extends Activity> extends ActivityInstrumentationTestCase2<A> {

    protected final String _TAG = this.getClass().getSimpleName();

    protected Solo mSolo;
    protected A mActivity;

    public SoloTestCase(String packageToTest, Class<A> clazz) {
        super(packageToTest, clazz);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        // Disable the statistic service
        GAHelper.sEnabled_NotForTesting = false;

        mActivity = getActivity();
        mSolo = new Solo(getInstrumentation(), mActivity);
    }

    @Override
    public void tearDown() throws Exception {
        try {
            if (mSolo != null) {
                //noinspection FinalizeCalledExplicitly
                mSolo.finalize();
            }
        } catch (Throwable e) {
            Log.e(_TAG, "tearDown solo failed", e);
        }
        getActivity().finish();
        super.tearDown();
    }

    public void assertThrow(Class<? extends Throwable> expected, Runnable r) {
        boolean gotException = false;
        try {
            r.run();
        } catch(Throwable actual) {
            gotException = true;
            if (!actual.getClass().equals(expected)) {
                fail("Expected exception " + expected.getSimpleName() + ", got " + actual.getClass().getSimpleName());
            }
        } finally {
            if (!gotException) {
                fail("Expected exception " + expected.getSimpleName() + ", got none.");
            }
        }
    }

    /**
     * Runs the given action, monitors activity starts for the given FQCN
     * (e.g. {@code MyActivity.class.getName()}. Returns the monitor hit
     * count, typically 1 on success.
     *
     * @param newActivity The activity class that should be started.
     * @param action The action that should start the activity.
     * @return The hit count of the activity monitor.
     */
    public int monitorActivityStart(Class<?> newActivity, Runnable action) {
        // Solo has its own catch-all monitor which we must remove and replace
        // by ours temporarily, then restore it back.
        ActivityMonitor soloMonitor = mSolo.getActivityMonitor();
        ActivityMonitor myMonitor = new ActivityMonitor(
                newActivity.getName(),
                null, // result
                true); // block
        try {
            getInstrumentation().removeMonitor(soloMonitor);
            getInstrumentation().addMonitor(myMonitor);
            assertEquals(0, myMonitor.getHits());

            action.run();

            getInstrumentation().waitForIdleSync();
            getInstrumentation().waitForMonitorWithTimeout(myMonitor, 1000);
            return myMonitor.getHits();
        } finally {
            getInstrumentation().removeMonitor(myMonitor);
            getInstrumentation().addMonitor(soloMonitor);
        }

    }
}
